//
//  MFAPMDataFactory.m
//  AFNetworking
//
//  Created by zhang liyu on 2019/5/27.
//

#import "MFAPMDataFactory.h"

#import "MFAPMScreenShotMonitorModel.h"
#import "MFAPMAppLifeCircleProtocol.h"
#import "MFAPMCrashMonitorModel.h"
#import "UIDevice+MFAPMUtility.h"
#import "MFAPMNetMonitorModel.h"
#import "MFAPMLocationMonitor.h"
#import "MFAPMUtility.h"
#import "MFAPMDefine.h"
#import <pthread.h>

static NSString *kMFAPMDataFactoryUserID = nil;
static NSString *kMFAPMDataFactoryRegion = nil;

static NSInteger serialStaticNUM;
static NSString *kMFAPMBaseModelStaticSerialNUMKey = @"kMFAPMBaseModelStaticSerialNUMKey";

@interface MFAPMDataFactory () <MFAPMAppLifeCircleProtocol>

@property (nonatomic, assign) pthread_mutex_t lock;

@property (nonatomic, assign) BOOL isFirstLoad;

@end

@implementation MFAPMDataFactory

#pragma mark - Singleton

+ (instancetype)sharedInstance{
    static MFAPMDataFactory *dataFactory = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        dataFactory = [[MFAPMDataFactory alloc] init];
    });
    return dataFactory;
}

#pragma mark - Life Circle

- (void)dealloc{
    [self removeNotifications];
}

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self updateStaticSerialNUM];
    });
}

- (instancetype)init{
    self = [super init];
    if(self){
        [self configActions];
    }
    return self;
}

- (void)configActions{
    _isFirstLoad = YES;
    //初始化时设定当前的地理定位信息为空字符串，避免地理定位字段重复获取
    kMFAPMDataFactoryRegion = @"";
    //注册通知，更新region信息
    [self registerNotifications];
}

#pragma mark - Notification Actions

- (void)registerNotifications{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDeviceRegion:) name:kMFAPMLocationMonitorRegionUpdateNotification object:nil];
}

- (void)removeNotifications{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)updateDeviceRegion:(NSNotification *)notification{
    NSString *regionDesc = notification.object;
    if(![regionDesc isKindOfClass:[NSString class]] || regionDesc.length == 0){
        return;
    }
    [MFAPMDataFactory updateRegion:regionDesc];
}

#pragma mark - Parameter Dictionary Config Actions

+ (NSDictionary *)configUploadRequestParametersDictFromDataArr:(NSArray<NSDictionary *> *)dataArr{
    NSMutableDictionary *resultParametersDict = [NSMutableDictionary dictionaryWithDictionary:[self configRequestCommonParameters]];
    [resultParametersDict setObject:[NSArray arrayWithArray:dataArr] forKey:@"data"];
    
    return [NSDictionary dictionaryWithDictionary:resultParametersDict];
}

+ (NSDictionary *)configParametersDictFromModel:(MFAPMBaseModel *)model{
    if(![model isKindOfClass:[MFAPMBaseModel class]] || model.timestamp <= 0){
        return nil;
    }
    //网络监听Model
    if([model isKindOfClass:[MFAPMNetMonitorModel class]]){
        return [self configNetMonitorUploadParametersDictFromNetModel:(MFAPMNetMonitorModel *)model];
    }
    //异常事件Model
    else if([model isKindOfClass:[MFAPMCrashMonitorModel class]]){
        return [self configCrashMonitorUploadParametersDictFromCrashModel:(MFAPMCrashMonitorModel *)model];
    }
    //截屏事件Model
    else if([model isKindOfClass:[MFAPMScreenShotMonitorModel class]]){
        return [self configScreenShotMonitorUploadParametersDictFromScreenShotMonitorModel:(MFAPMScreenShotMonitorModel *)model];
    }
    //其他均按照BaseModel进行处理
    else{
        return [self configBaseModelUploadParametersDictFromBaseModel:model];
    }
    
    return nil;
}

+ (NSDictionary *)configNetMonitorUploadParametersDictFromNetModel:(MFAPMNetMonitorModel * _Nonnull)netModel{
    
    if(![netModel isKindOfClass:[MFAPMNetMonitorModel class]] || netModel.timestamp <= 0){
        return nil;
    }
    NSMutableDictionary *resultParametersDict = [NSMutableDictionary dictionaryWithDictionary:[self configBaseModelCommonParametersFromBaseModel:netModel]];
    
    [resultParametersDict setObject:@(netModel.requestMode) forKey:@"requestMode"];
    
    [resultParametersDict setObject:@(netModel.requestSource) forKey:@"requestSource"];
    
    [resultParametersDict setObject:(netModel.requestMethod ? : @"") forKey:@"requestMethod"];
    
    [resultParametersDict setObject:(netModel.url ? : @"") forKey:@"url"];
    
    [resultParametersDict setObject:(netModel.domain ? : @"") forKey:@"domain"];
    
    [resultParametersDict setObject:(netModel.ip ? : @"") forKey:@"ip"];
    
    [resultParametersDict setObject:(netModel.statusCode ? : @"") forKey:@"statusCode"];
    
    [resultParametersDict setObject:(netModel.requestParameter ? : @"") forKey:@"requestParameter"];
    
    [resultParametersDict setObject:(netModel.requestBody ? : @"") forKey:@"requestBody"];
    
    [resultParametersDict setObject:(netModel.requestHeaders ? : @"") forKey:@"requestHeaders"];
    
    [resultParametersDict setObject:(netModel.responseCode ? : @"") forKey:@"responseCode"];
    
    [resultParametersDict setObject:(netModel.responseMessage ? : @"") forKey:@"responseMessage"];
    
    [resultParametersDict setObject:(netModel.responseBody ? : @"") forKey:@"responseBody"];
    
    [resultParametersDict setObject:(netModel.responseMIMEType ? : @"") forKey:@"responseMIMEType"];
    
    return [NSDictionary dictionaryWithDictionary:resultParametersDict];
}

+ (NSDictionary *)configCrashMonitorUploadParametersDictFromCrashModel:(MFAPMCrashMonitorModel * _Nonnull)crashModel{
    
    if(![crashModel isKindOfClass:[MFAPMCrashMonitorModel class]] || crashModel.timestamp <= 0){
        return nil;
    }
    NSMutableDictionary *resultParametersDict = [NSMutableDictionary dictionaryWithDictionary:[self configBaseModelCommonParametersFromBaseModel:crashModel]];
    
    [resultParametersDict setObject:(crashModel.cpuRate ? : @"") forKey:@"cpuRate"];
    
    [resultParametersDict setObject:(crashModel.memoryRate ? : @"") forKey:@"memoryRate"];
    
    [resultParametersDict setObject:(crashModel.exception ? : @"") forKey:@"exception"];
    
    [resultParametersDict setObject:(crashModel.stack ? : @"") forKey:@"stack"];
    
    [resultParametersDict setObject:(crashModel.systemStack ? : @"") forKey:@"systemStack"];
    
    [resultParametersDict setObject:(crashModel.extend ? : @"") forKey:@"extend"];
    
    [resultParametersDict setObject:(crashModel.threadName ? : @"") forKey:@"threadName"];
    
    [resultParametersDict setObject:(crashModel.processName ? : @"") forKey:@"processName"];
    
    return [NSDictionary dictionaryWithDictionary:resultParametersDict];
}

+ (NSDictionary *)configScreenShotMonitorUploadParametersDictFromScreenShotMonitorModel:(MFAPMScreenShotMonitorModel * _Nonnull)screenShotMonitorModel{
    if(![screenShotMonitorModel isKindOfClass:[MFAPMScreenShotMonitorModel class]] || screenShotMonitorModel.timestamp <= 0){
        return nil;
    }
    NSMutableDictionary *resultParametersDict = [NSMutableDictionary dictionaryWithDictionary:[self configBaseModelCommonParametersFromBaseModel:screenShotMonitorModel]];
    
    [resultParametersDict setObject:(screenShotMonitorModel.vc ? : @"") forKey:@"vc"];
    
    //解析截图相关请求数组
    NSMutableArray *requestItemsArr = [NSMutableArray array];
    for (MFAPMNetMonitorModel *netMonitorModel in screenShotMonitorModel.request) {
        
        if([netMonitorModel isKindOfClass:[MFAPMNetMonitorModel class]] && netMonitorModel.timestamp > 0){
            
            NSMutableDictionary *requestItemDict = [NSMutableDictionary dictionary];
            
            [requestItemDict setObject:(netMonitorModel.requestParameter ? : @"") forKey:@"requestParameter"];
            
            [requestItemDict setObject:(netMonitorModel.requestBody ? : @"") forKey:@"requestBody"];
            
            [requestItemDict setObject:(netMonitorModel.requestHeaders ? : @"") forKey:@"requestHeaders"];
            
            [requestItemDict setObject:(netMonitorModel.responseBody ? : @"") forKey:@"responseBody"];
            
            [requestItemsArr addObject:requestItemDict];
        }
    }
    [resultParametersDict setObject:requestItemsArr forKey:@"request"];
    
    [resultParametersDict setObject:(screenShotMonitorModel.file ? : @"") forKey:@"file"];
    
    return [NSDictionary dictionaryWithDictionary:resultParametersDict];
}

+ (NSDictionary *)configBaseModelUploadParametersDictFromBaseModel:(MFAPMBaseModel * _Nonnull)baseModel{
    if(![baseModel isKindOfClass:[MFAPMBaseModel class]] || baseModel.timestamp <= 0){
        return nil;
    }
    return [self configBaseModelCommonParametersFromBaseModel:baseModel];
}

#pragma mark - Common Parameter Actions

/**
 *  获取当前设备的运营商编码
 */
+ (NSInteger)networkOperator{
    static NSInteger operator = -1;
    if(operator <= 0){
        operator = [[UIDevice mfapm_getDeviceCarrierCodeName] integerValue];
    }
    return operator;
}

/**
 *  更新当前设备的定位信息
 */
+ (void)updateRegion:(NSString *)region{
    @synchronized (kMFAPMDataFactoryRegion) {
        kMFAPMDataFactoryRegion = region.length > 0 ? [region copy] : @"";
    }
}

/**
 *  获取当前设备的定位信息
 */
+ (NSString *)region{
    static NSString *region = nil;
    @synchronized (kMFAPMDataFactoryRegion) {
        //当前定位信息不同时，进行对应数据的更新操作
        if(![region isEqualToString:kMFAPMDataFactoryRegion]){
            region = [kMFAPMDataFactoryRegion copy] ? : @"";
        }
    }
    return region;
}

/**
 *  获取当前设备的UUID
 */
+ (NSString *)UUIDValue{
    static NSString *UUID = nil;
    if(UUID.length == 0){
        UUID = [UIDevice mfapm_getDeviceUUID] ? : @"";
    }
    return UUID;
}

/**
 *  获取当前设备的操作系统版本号
 */
+ (NSString *)OSVersion{
    static NSString *osVersion = nil;
    if(osVersion.length == 0){
        osVersion = [UIDevice mfapm_getDeviceOSVersion] ? : @"";
    }
    return osVersion;
}

/**
 *  获取当前设备的型号名称
 */
+ (NSString *)deviceName{
    static NSString *deviceName = nil;
    if(deviceName.length == 0){
        deviceName = [UIDevice mfapm_getDeviceName] ? : @"";
    }
    return deviceName;
}

/**
 *  获取当前App的版本号信息
 */
+ (NSString *)appVersion{
    static NSString *version = nil;
    if(version.length == 0){
        version = [UIDevice mfapm_getAppVersion] ? : @"";
    }
    return version;
}

/**
 *  获取当前App的名称信息
 */
+ (NSString *)appDisplayName{
    static NSString *displayName = nil;
    if(displayName.length == 0){
        displayName = [UIDevice mfapm_getAppDisplayName] ? : @"";
    }
    return displayName;
}

/**
 更新USerID字段
 */
+ (void)updateUserID:(nullable NSString *)userID{
    @synchronized (kMFAPMDataFactoryUserID) {
        kMFAPMDataFactoryUserID = userID.length > 0 ? [userID copy] : [[self UUIDValue] copy];
    }
}

/**
 返回UserID字段
 */
+ (NSString *)userID{
    static NSString *userID = nil;
    @synchronized (kMFAPMDataFactoryUserID) {
        if(![userID isEqualToString:kMFAPMDataFactoryUserID]){
            userID = [kMFAPMDataFactoryUserID copy] ? : @"";
        }
    }
    return userID;
}

/**
 事件序列号，自动加一
 */
+ (NSInteger)serialNUM{
    NSInteger num = -1;
    pthread_mutex_lock([MFAPMDataFactory sharedInstance].mutexLock);
    num = (++serialStaticNUM);
    pthread_mutex_unlock([MFAPMDataFactory sharedInstance].mutexLock);
    return num;
}

/**
 当前的事件序列号
 */
+ (NSInteger)staticSerialNUM{
    NSInteger num = -1;
    pthread_mutex_lock([MFAPMDataFactory sharedInstance].mutexLock);
    num = serialStaticNUM;
    pthread_mutex_unlock([MFAPMDataFactory sharedInstance].mutexLock);
    return num;
}

/**
 更新当前的事件序号静态变量
 */
+ (void)configStaticSerialNUM:(NSInteger)serialNUM{
    pthread_mutex_lock([MFAPMDataFactory sharedInstance].mutexLock);
    serialStaticNUM = serialNUM;
    pthread_mutex_unlock([MFAPMDataFactory sharedInstance].mutexLock);
}

/**
 生成数据公共属性字段
 */
+ (NSDictionary *)configBaseModelCommonParametersFromBaseModel:(MFAPMBaseModel *)baseModel{
    
    NSMutableDictionary *commonDataDict = [NSMutableDictionary dictionary];
    
    [commonDataDict setObject:@(baseModel.eventType) forKey:@"eventType"];
    
    [commonDataDict setObject:@(baseModel.timestamp) forKey:@"timestamp"];
    
    [commonDataDict setObject:@(self.serialNUM) forKey:@"serialNum"];
    
    [commonDataDict setObject:@(baseModel.network) forKey:@"network"];
    
    [commonDataDict setObject:@(self.networkOperator) forKey:@"networkOperator"];
    
    [commonDataDict setObject:(baseModel.userId ? : @"") forKey:@"userId"];
    
    [commonDataDict setObject:(self.region ? : @"") forKey:@"region"];
    
    return [NSDictionary dictionaryWithDictionary:commonDataDict];
}

/**
 返回请求通用参数字段
 */
+ (NSDictionary *)configRequestCommonParameters{
    
    static NSMutableDictionary *commonParametersDict = nil;
    
    //初始化固定字符串
    if(commonParametersDict.count == 0){
        
        commonParametersDict = [NSMutableDictionary dictionary];
        
        [commonParametersDict setObject:MFAPM_APP_KEY forKey:@"appKey"];
        
        [commonParametersDict setObject:[self appDisplayName] forKey:@"appName"];
        
        [commonParametersDict setObject:[self appVersion] forKey:@"appVersion"];
        
        [commonParametersDict setObject:[self deviceName] forKey:@"deviceMode"];
        
        [commonParametersDict setObject:[self OSVersion] forKey:@"osVersion"];
        
        //平台/类型：1(Android)、2(IOS)、3(H5)
        [commonParametersDict setObject:@(2) forKey:@"platform"];
        
        [commonParametersDict setObject:[self UUIDValue] forKey:@"imei"];
    }
    return [NSDictionary dictionaryWithDictionary:commonParametersDict];
}

#pragma mark - Event Serial NUM Actions

+ (void)updateStaticSerialNUM{
    
    NSDictionary *serialNUMDataDict = [self fetchStaticSerialNUMDataDict];
    NSDate *currentDate = [NSDate date];
    
    //存在缓存数据，进行比较，当天数不一致时，进行序号的重置及序号数据的缓存
    if(serialNUMDataDict){
        NSTimeInterval oldTimeStamp = [serialNUMDataDict[@"timeStamp"] doubleValue];
        //判断是否为相同的年月日
        BOOL isSameDate = [MFAPMUtility checkIsSameDate:[NSDate dateWithTimeIntervalSince1970:oldTimeStamp] withDate:currentDate];
        //同一天时更新保存的事件NUM
        if(isSameDate){
            NSInteger saveNUM = [serialNUMDataDict[@"serialNUM"] unsignedIntegerValue];
            //同步事件NUM
            if(saveNUM > self.staticSerialNUM){
                [self configStaticSerialNUM:saveNUM];
            }else if (saveNUM < self.staticSerialNUM){
                [self storeStaticSerialNUMWithDate:currentDate];
            }
            
            //清空数据
            serialNUMDataDict = nil;
            currentDate = nil;
            
            return;
        }
    }
    
    //清空数据
    serialNUMDataDict = nil;
    currentDate = nil;
    
    //当为不同年月日或当前并未缓存NUM数据时，进行NUM数据重置及数据的缓存
    [self configStaticSerialNUM:0];
    [self storeStaticSerialNUMWithDate:currentDate];
}

+ (void)storeStaticSerialNUMWithDate:(NSDate *)date{
    NSDate *stampDate = date ? : [NSDate date];
    NSString *newTimeStamp = [NSString stringWithFormat:@"%lf",[stampDate timeIntervalSince1970]];
    [self storeStaticSerialNUMDataWithDict:@{
                                             @"timeStamp" : newTimeStamp,
                                             @"serialNUM" : @(self.staticSerialNUM),
                                             }];
    
    //清空数据
    stampDate = nil;
    newTimeStamp = nil;
}

#pragma mark - App Life Circle Actions

- (void)appDidBecomeActive:(NSNotification *)notification{
    //首次启动，num在Load方法中已经加载，不进行重复加载处理
    if([MFAPMDataFactory sharedInstance].isFirstLoad){
        [MFAPMDataFactory sharedInstance].isFirstLoad = NO;
        return;
    }
    [MFAPMDataFactory updateStaticSerialNUM];
}

- (void)appWillResignActive:(NSNotification *)notification{
    [MFAPMDataFactory storeStaticSerialNUMWithDate:nil];
}

- (void)appWillTerminate:(NSNotification *)notification{
    [MFAPMDataFactory storeStaticSerialNUMWithDate:nil];
}

#pragma mark - Setter & Getter

+ (NSDictionary *)fetchStaticSerialNUMDataDict{
    NSDictionary *userDefaultDict = [MFAPMUtility userDefaultObjForKey:kMFAPMBaseModelStaticSerialNUMKey];
    if(![userDefaultDict isKindOfClass:[NSDictionary class]] || userDefaultDict.count == 0){
        return nil;
    }
    return [NSDictionary dictionaryWithObjectsAndKeys:
            userDefaultDict[@"timeStamp"], @"timeStamp",
            userDefaultDict[@"serialNUM"], @"serialNUM", nil];
}

+ (void)storeStaticSerialNUMDataWithDict:(NSDictionary *)dataDict{
    if(![dataDict isKindOfClass:[NSDictionary class]] || dataDict.count == 0){
        return;
    }
    [MFAPMUtility userDefaultStore:[NSDictionary dictionaryWithDictionary:dataDict] forKey:kMFAPMBaseModelStaticSerialNUMKey];
}

- (pthread_mutex_t *)mutexLock{
    if(!(&_lock)){
        pthread_mutex_init(&_lock, NULL);
    }
    return &_lock;
}


@end
